﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace DTBuilderLib.VisualHierarchyClasses
{
    /// <summary>
    /// Base class for a single image.
    /// </summary>
    [Serializable]
    abstract public class Visual : IEnumerable<Visual>
    {
        public Visual()
        {
            IsCompositionUnit = false;
        }

        /// <summary>
        /// Get the current width of the image (in inches).
        /// </summary>
        public abstract double Width
        {
            get;
        }

        /// <summary>
        /// Get the current height of the image (in inches).
        /// </summary>
        public abstract double Height
        {
            get;
        }

        /// <summary>
        /// Get the curretn x position (in inches).
        /// </summary>
        public abstract double XPosition
        {
            get;
            set;
        }

        /// <summary>
        /// Get current y positition (in inches).
        /// </summary>
        public abstract double YPosition
        {
            get;
            set;
        }

        /// <summary>
        /// Enlarge or shrink the image. Keeps the apsect ratio.
        /// </summary>
        /// <param name="factor">If greater 1 then it gets larger, If less than 1 it gets smaller.</param>
        public abstract void Scale(double factor);

        /// <summary>
        /// Returns all the sceen graph nodes that make this guy up.
        /// </summary>
        internal abstract List<SceneGraphSceneNode> SGNodeList
        {
            get;
        }

        /// <summary>
        /// Change the z index by some number
        /// </summary>
        /// <param name="delta"></param>
        public abstract void IncZIndex(int delta);

        /// <summary>
        /// Short cut to inc by one.
        /// </summary>
        public void IncZIndex()
        {
            IncZIndex(1);
        }

        public abstract int ZIndex
        {
            get;
        }

        /// <summary>
        /// Set to true if you would like the images here and below to be treated as a
        /// single composition.
        /// </summary>
        public bool IsCompositionUnit
        { get; set; }

        /// <summary>
        /// Gets an enumerator that will return all the sub-visuals.
        /// </summary>
        /// <returns></returns>
        public virtual System.Collections.Generic.IEnumerator<Visual> GetEnumerator()
        {
            yield return this;
        }

        /// <summary>
        /// Return an enumerator that will find only those guys that don't pass a certian test - those it will
        /// return, but it won't look "into" them.
        /// </summary>
        /// <param name="test"></param>
        /// <returns></returns>
        public IEnumerable<Visual> GetHierarchicalEnumerator(Func<Visual, bool> test)
        {
            return new VisualHierarchyConditional(this, test);
        }

        /// <summary>
        /// Makes it possible to list all the various visual elements. It doesn't go "down" one
        /// when it finds a match with the function. THis is deep -- it will flatten the tree
        /// until it hits a certian condition and then it won't try to go any deeper.
        /// </summary>
        protected class VisualHierarchyConditional : IEnumerable<Visual>
        {
            private Visual _root;
            private Func<Visual, bool> _test;

            public VisualHierarchyConditional(Visual root, Func<Visual, bool> test)
            {
                _test = test;
                _root = root;
            }

            /// <summary>
            /// Gets the next guy, and goes no deeper if it satisfies the condition too.
            /// </summary>
            /// <returns></returns>
            public IEnumerator<Visual> GetEnumerator()
            {
                if (_test(_root))
                {
                    yield return _root;
                }
                else
                {
                    foreach (var v in _root)
                    {
                        if (v == _root)
                        {
                            yield return v;
                        }
                        else
                        {
                            VisualHierarchyConditional matcher = new VisualHierarchyConditional(v, _test);
                            foreach (var vsub in matcher)
                            {
                                yield return vsub;
                            }
                        }
                    }
                }
            }

            System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
            {
                return this.GetEnumerator();
            }
        }

        /// <summary>
        /// A short name for this visual. Should be suitible for a file system.
        /// </summary>
        public string ShortName { get; set; }

        /// <summary>
        /// Returns true if the name contains something decent.
        /// </summary>
        public bool ShortNameGood
        {
            get
            {
                return ShortName != null && ShortName.Length > 0;
            }
        }

        /// <summary>
        /// A short name for this visual. Should be suitible for a file system.
        /// </summary>
        public string Title { get; set; }

        /// <summary>
        /// Returns true if the name contains something decent.
        /// </summary>
        public bool TitleGood
        {
            get
            {
                return Title != null && Title.Length > 0;
            }
        }
        #region IEnumerable Members

        System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
        {
            throw new NotImplementedException();
        }

        #endregion
    }
}
